package routes

import (
	"database/sql"
	"errors"
	"fmt"
	"gitee.com/gitee-go/core"
	"gitee.com/gitee-go/core/common"
	"gitee.com/gitee-go/core/dbcore"
	"gitee.com/gitee-go/server/comm"
	"gitee.com/gitee-go/utils"
	"github.com/gin-gonic/gin"
	_ "github.com/go-sql-driver/mysql"
	"github.com/golang-migrate/migrate/v4"
	"github.com/golang-migrate/migrate/v4/database/mysql"
	_ "github.com/golang-migrate/migrate/v4/source/file"
	bindata "github.com/golang-migrate/migrate/v4/source/go_bindata"
)

/**
数据库安装
默认给了docker-compose的变量
*/
func (cs *InstallController) datas(c *gin.Context, m comm.DataSourceConf) {
	if m.Host == "" {
		m.Host = utils.EnvDefault("MYSQL_HOST", "database")
	}
	if m.Port == "" {
		m.Port = utils.EnvDefault("MYSQL_PORT", "3306")
	}
	if m.Database == "" {
		m.Database = utils.EnvDefault("MYSQL_DATABASE", "giteego")
	}
	if m.Username == "" {
		m.Username = utils.EnvDefault("MYSQL_USER", "root")
	}
	if m.Password == "" {
		m.Password = utils.EnvDefault("MYSQL_PASSWORD")
		if m.Password == "" {
			m.Password = utils.EnvDefault("MYSQL_ROOT_PASSWORD")
		}
	}
	if m.Host == "" || m.Port == "" || m.Database == "" {
		core.NewUIRes(common.UICodeErrParam).
			ResJson(c)
		return
	}
	dbwait, err := initMigrate(&m)
	if err != nil {
		if dbwait {
			core.NewUIRes(common.UICodeInstallWait).
				ResJson(c)
		} else {
			core.NewUIRes(common.UICodeErrs).
				SetMsgObjs(err).
				ResJson(c)
		}
		return
	}
	err = initDB(&m)
	if err != nil {
		core.NewUIRes(common.UICodeErrs).
			SetMsgObjs(err).
			ResJson(c)
		return
	}
	cs.ymlConf.DataConf = &m

	core.NewUIResOk().ResJson(c)
}
func initMigrate(m *comm.DataSourceConf) (bool, error) {
	if m == nil {
		return false, errors.New("database config not found")
	}
	ul := fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?parseTime=true&multiStatements=true",
		m.Username,
		m.Password,
		m.Host,
		m.Port,
		m.Database)
	println("connect db:" + ul)
	db, err := sql.Open("mysql", ul)
	if err != nil {
		//core.Log.Errorf("could not connect to postgresql database... %v", err)
		println("open db err:" + err.Error())
		return true, err
	}
	err = db.Ping()
	if err != nil {
		db.Close()
		uls := fmt.Sprintf("%s:%s@tcp(%s:%s)/?parseTime=true&multiStatements=true",
			m.Username,
			m.Password,
			m.Host,
			m.Port)
		db, err = sql.Open("mysql", uls)
		if err != nil {
			println("open dbs err:" + err.Error())
			return true, err
		}
		defer db.Close()
		_, err = db.Exec(fmt.Sprintf("CREATE DATABASE `%s` DEFAULT CHARACTER SET utf8mb4;", m.Database))
		if err != nil {
			println("create dbs err:" + err.Error())
			return true, err
		}
		db.Exec(fmt.Sprintf("USE `%s`;", m.Database))
		err = db.Ping()
	}
	defer db.Close()
	if err != nil {
		return false, err
	}

	// Run migrations
	driver, err := mysql.WithInstance(db, &mysql.Config{})
	if err != nil {
		println("could not start sql migration... ", err.Error())
		return false, err
	}

	s := bindata.Resource(comm.AssetNames(), comm.Asset)
	sc, err := bindata.WithInstance(s)
	if err != nil {
		return false, err
	}
	mgt, err := migrate.NewWithInstance(
		"bindata", sc,
		"mysql", driver)

	if err != nil {
		return false, err
	}
	err = mgt.Up()
	if err != nil && err != migrate.ErrNoChange {
		mgt.Down()
		return false, err
	}

	return false, nil
}

func initDB(cf *comm.DataSourceConf) error {
	if comm.DBMain != nil {
		return nil
	}
	ul := fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?parseTime=true",
		cf.Username,
		cf.Password,
		cf.Host,
		cf.Port,
		cf.Database)
	mysqlDB, err := dbcore.InitMysql(ul, cf.ShowSQL)
	if err != nil {
		core.Log.Errorf("InitMysql err:%v", err)
		return err
	}
	comm.DBMain = dbcore.NewDBHelper(mysqlDB)
	return nil
}
